import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class mainTest {
    public static void main(String[] args) {

        //System.out.println(HeartBeatModule.HB_WAIT_TIME);//随便调用一个HeartBeatModule类中的static块,就会触发类加载
        try {
            //创建心跳模块
            Class.forName("HeartBeatModule");//调用一个Class.forName()函数,也会触发类加载的"初始化"(执行静态代码块)
            Class.forName("ControlConnectionModule");
            Class.forName("SendFileQueueMap");
            Class.forName("ReciveFileQueue");
            Class.forName("SendFileConnInfoMap");
            Class.forName("SendFilePool");
            Class.forName("RcvFileWriteThread");
            Class.forName("FileHoldingListSelfMap");//"自己的文件持有表"管理map 也会同时开始执行 "自己的文件持有表本地扫描" "自己的文件持有表发送"
            Class.forName("FCL_S_ReceiverQueue");//"自己的文件持有表"接收消息队列创建
            Class.forName("FCL_S_Receiver");//"自己的文件持有表"接收线程
            Class.forName("FileHoldingListPublicMap");//"全网文件片持有表"管理map
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }


        //1：创建服务器的套接字
        ServerSocket ss = null;
        try {
            ss = new ServerSocket(8585);
            //2:监听客户端的套接字,并且返回客户端的套接字
            Socket s_t = ss.accept();  //阻塞式方法
            Thread thread = new Thread(new ControlConnectionThread(s_t, 1));
            thread.start();

            //main函数中测试"文件发送基础设施"
            //从 [管理所有"文件发送连接"的map] 拿到三条个文件发送模块的BufferOutputSTream和socket
            SendFileConnInfoMap.SFInfo info = SendFileConnInfoMap.getMap().get(s_t.getInetAddress().toString());
            System.out.println(info);//报空指针....我懂了,这个位置,"初始化线程"还没执行完呢

            thread.join();
            //从 [管理所有"文件发送连接"的map] 拿到三条个文件发送模块的BufferOutputSTream和socket
            info = SendFileConnInfoMap.getMap().get(s_t.getInetAddress().toString());
            //直接把线程池拿来创建任务
            ExecutorService send_file_pool = SendFilePool.getPool();
            System.out.println(send_file_pool);
            send_file_pool.execute(new SendFileThread(info.file_conn_arr[0], info.bos_arr[0]));
            send_file_pool.execute(new SendFileThread(info.file_conn_arr[1], info.bos_arr[1]));
            send_file_pool.execute(new SendFileThread(info.file_conn_arr[2], info.bos_arr[2]));

            //拿到客户端s_t的文件发送队列管理map
            Map<String, BlockingQueue<byte[]>> sendFileQueueMap = SendFileQueueMap.getMap();
            BlockingQueue<byte[]> send_file_queue = sendFileQueueMap.get(s_t.getInetAddress().toString());

            while (true) {
                //扫描一个文件夹内的所有文件片,全部发过去(复制的是FileSplitMerge的代码)
                //事实上,之后真正的发送环境不是每次发送都扫描本地文件夹(这样太慢了)
                //而应该是从FileHoldingListSelf对象中,直接读取到文件片的存储绝对地址
                String path = FileSplitMerge.class.getResource("/").getPath() + File.separator + "07FD69AD27BF2F633A20A2A4F3FC4807" + File.separator;
                //STEP1 文件名的正则表达式(文件名全是数字)
                String filename_regular = "\\d+";
                //STEP2 列出路径中所有文件 file是一个路径
                File file_path = new File(path);
                if (!file_path.isDirectory()) {
                    System.out.println("文件片文件夹不合法");
                    break;
                }
                String name = file_path.getName();
                System.out.println(name);
                String[] list = file_path.list();//列出路径中所有文件  File.list()此方法的返回类型为File []，即，如果给定路径为目录，则返回文件路径中表示的文件数组，否则返回null。
                //STEP2 利用"Stream"的方法进行正则表达式匹配,筛选出符合正则表达式的文件名,存入List subFileNames
                Stream<String> stream = Arrays.stream(list);

                class item {//用于排序的临时内部来
                    String filename;
                    int val;

                    public int getVal() {
                        return val;
                    }

                    public String getFilename() {
                        return filename;
                    }

                    item(String s) {
                        filename = s;
                        val = Integer.parseInt(filename);
                    }
                }
                List<item> item_list = stream.filter(str -> {
                    return str.matches(filename_regular);
                }).map(str -> new item(str)).collect(Collectors.toList());
                List<String> filename_array = item_list.stream().sorted(Comparator.comparing(item::getVal)).map(item::getFilename).collect(Collectors.toList());

                filename_array.forEach(i -> {
                    System.out.println(i);
                });

                if (filename_array == null || filename_array.size() < 1) {
                    break;
                }
                for (String subFilename : filename_array){
                    BufferedInputStream bis = new BufferedInputStream(new FileInputStream(path + subFilename));
                    int total_length = bis.available();
                    System.out.println(total_length);
                    byte[] s_ba = new byte[total_length];
                    bis.read(s_ba);
                    byte[] ba = MessageEncapsulationUtils.MessageToChunk(s_ba);//包装为可发送的块
                    send_file_queue.add(ba);

                }
                Thread.sleep(1000);
                break;

//                //随便向文件发送队列发个包
//                byte[] s_ba = MessageEncapsulationUtils.MessageToChunk(new byte[]{98, 97, 98});//调用了封装消息的函数
//                send_file_queue.add(s_ba);
//                send_file_queue.add(s_ba);
//                send_file_queue.add(s_ba);
//                send_file_queue.add(s_ba);
//                send_file_queue.add(s_ba);
//                send_file_queue.add(s_ba);
                //循环侦听新的客户端的连接
                //Map<String,SendQueue> send_queue_map = ControlConnectionModule.getInstance().SendQueue_map;
                //for (Map.Entry<String,SendQueue> entry : send_queue_map.entrySet()) {
                //    entry.getValue().put(MessageEncapsulationUtils.MessageToChunk(MessageEncapsulationUtils.HeartBeatMessage_pack(10)));
                //}

            }


        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
        }
    }
}
